package com.yunti.business.service.impl;

import com.alibaba.fastjson2.JSON;
import com.yunti.business.vo.req.WsMessage;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.stream.Collectors;


/**
 * 双工通信websocket工具类
 *
 * @author wwl
 */
//@CrossOrigin
@ServerEndpoint(value = "/webSocket/{id}")
@Slf4j
@Component
@Data
public class WebSocketService {
    @Resource
    protected StringRedisTemplate stringRedisTemplate;
    /**
     * 静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。
     */
    private static int onlineCount = 0;

    /**
     * concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。
     */
    public static Set<WebSocketService> set = new CopyOnWriteArraySet<>();
    /**
     * 与某个客户端的连接会话，需要通过它来给客户端发送数据
     */
    private Session session;
    private String id;

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(@PathParam("id") String id, Session session) {
        this.session = session;
        this.id = id;
        set.add(this);
        addOnlineCount();
        log.info("ID：{}连接加入！当前在线人数为{}", id, getOnlineCount());
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        //从map中删除
        set.remove(this);
        //在线数减1
        subOnlineCount();
        log.info("{}连接关闭！当前在线人数为{}", this.id, getOnlineCount());
    }

    /**
     * 服务端群发消息调用的方法
     *
     * @param message 服务端群发消息
     */
    @OnMessage
    public void onMessage(String message) {
        log.info("服务端群发消息：{}", message);
    }

    /**
     * 发生错误时调用
     */
    @OnError
    public void onError(@PathParam("id") String raceId, Session session, Throwable error) {
        log.info("id：{},session：{}发生错误或断开连接,错误详情：{}", raceId, session, error);
        optClose(session);
    }


    /**
     * 发自定义消息
     */
    public void sendInfo(WsMessage req) {
        List<WebSocketService> list = set.stream().filter((e) -> {
            return Objects.equals(e.getId(), req.getAcceptId());
        }).collect(Collectors.toList());
        new Thread(() -> {
            for (WebSocketService webSocket : list) {
                if (webSocket != null) {
                    try {
                        webSocket.session.getBasicRemote().sendText(JSON.toJSONString(req));
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    log.info("接收者ID：{},消息{}", req.getAcceptId(), JSON.toJSONString(req));
                }
            }
        }).start();
    }


    /**
     * 操作进行下线
     *
     * @param session
     */

    public static void optClose(Session session) {
        // 判断当前连接是否还在线
        if (session.isOpen()) {
            try {
                // 关闭连接
                CloseReason closeReason = new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, "鉴权失败！");
                session.close(closeReason);
            } catch (IOException e) {
                e.printStackTrace();

            }

        }

    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketService.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketService.onlineCount--;
    }

}
